package com.biye.api.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.base.common.edu.entity.SftpAccount;
import com.base.common.edu.entity.Staff;
import com.base.common.edu.mapper.SftpAccountMapper;
import com.base.common.edu.util.Dateutil;
import com.base.common.edu.util.Page;
import com.base.common.httpStatusCode.enumDefine.StatusCode;
import com.biye.api.service.SFTPService;
import com.biye.api.tool.sftp.SFTPUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

@Service
@Transactional
public class SFTPServiceImpl implements SFTPService {

    @Resource
    private SftpAccountMapper sftpAccountMapper;

    @Override
    public JSONObject manageSFTPAccount(Map<String, Object> requestMap, JSONObject json__body) {
        JSONObject json = new JSONObject();
        String msg = StatusCode.Failure.explain;
        int statusCode = StatusCode.Failure._statusCode;
        // 判断请求参数是否合法
        if ( !requestMap.containsKey("username") || !requestMap.containsKey("user_id") || !requestMap.containsKey("oprate_type")) {
            json.put("msg", "请求参数有误请检查");
            json.put("statusCode", statusCode);
            return json;
        }
        // 取出请求参数-用户名
        String username = (String) requestMap.get("username");
        String user_id = (String) requestMap.get("user_id");
        // 首先判断操作类型
        String operation_type = (String) requestMap.get("oprate_type");
        if ( "add".equals(operation_type) ) {
            if ( !requestMap.containsKey("password") || "".equals(requestMap.get("password"))){
                json.put("msg", "请求参数有误请检查");
                json.put("statusCode", statusCode);
                return json;
            }
            // 添加用户时判断-数据库是否有该用户
            SftpAccount sftpAccount = new SftpAccount();
            sftpAccount.setSftpUsername(username);
            Staff staff = new Staff();
            staff.setStaffId(user_id);
            sftpAccount.setStaff(staff);
            List<SftpAccount> sftpAccounts = sftpAccountMapper.querySftpAccount(sftpAccount);
            if ( sftpAccounts.size() > 0  ){
                // 该账户已存在，不能重复创建，PASS
            }else{
                // 若数据库没有该用户时，根据RPC的结果来创建
                boolean rpc_result = json__body.getBoolean("result");
                if ( rpc_result ) {
                    statusCode = 1;
                    json.put("rpc_msg", json__body.getString("msg"));
                    String password = (String) requestMap.get("password");
                    sftpAccount.setSftpPassword(password);
                    sftpAccount.setActivateStatus(1);
                    sftpAccountMapper.addSftpAccount(sftpAccount);
                }
            }
            msg = "添加操作完成";
        } else if ( "del".equals(operation_type) ){
            // 添加用户时判断-数据库是否有该用户
            SftpAccount sftpAccount = new SftpAccount();
            sftpAccount.setSftpUsername(username);
            Staff staff = new Staff();
            staff.setStaffId(user_id);
            sftpAccount.setStaff(staff);
            List<SftpAccount> sftpAccounts = sftpAccountMapper.querySftpAccount(sftpAccount);
            if ( sftpAccounts.size() > 0  ){
                // 该账户已存在，则删除该用户
                boolean rpc_result = json__body.getBoolean("result");
                if ( rpc_result ) {
                    statusCode = 1;
                    json.put("rpc_msg", json__body.getString("msg"));
                    Integer s_a_m_id = sftpAccounts.get(0).getS_a_m_id();
                    sftpAccountMapper.delSftpAccount(s_a_m_id);
                }
            }else{
                // 若数据库没有该用户时，PASS
            }
            msg = "掺除操作完成";
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json;
    }

    @Override
    public String querySFTPAccount(Map<String, Object> requestMap) {
        JSONObject json = new JSONObject();
        String msg = StatusCode.Failure.explain;
        int statusCode = StatusCode.Failure._statusCode;
        // 判断参数是否正确
        if ( !requestMap.containsKey("pageNum") || !requestMap.containsKey("pageSize") || !requestMap.containsKey("username") || !requestMap.containsKey("activate_status") ) {
            json.put("msg", "请求参数不正确");
            json.put("statusCode", statusCode);
            return json.toJSONString();
        }
        // 分页查询参数
        int pageNum = (int) requestMap.get("pageNum");
        int pageSize = (int) requestMap.get("pageSize");
        String username = (String) requestMap.get("username");
        int activate_status = (int) requestMap.get("activate_status");
        SftpAccount sftpAccount = new SftpAccount();
        if ( !"".equals(username) )
            sftpAccount.setSftpUsername(username);
        if (activate_status == -1 || activate_status == 0 || activate_status == 1)
            sftpAccount.setActivateStatus(activate_status);
        PageHelper.startPage(pageNum, pageSize);
        List<SftpAccount> sftpAccounts = sftpAccountMapper.querySftpAccount(sftpAccount);
        PageInfo<SftpAccount> pageInfo = new PageInfo<>(sftpAccounts);
        if (sftpAccounts.size() > 0 ){
            // 由于想自定义分页参数，所以这边只把数据查出来，后边自己封装
            Page<Map<String, Object>> p = new Page<Map<String, Object>>(pageNum, pageSize, (int) pageInfo.getTotal());
            List<Map<String, Object>> sa_list = new ArrayList<>();
            Map<String, Object> map_obj;
            for ( SftpAccount sa : sftpAccounts ) {
                map_obj = new HashMap<>();
                map_obj.put("s_a_m_id", sa.getS_a_m_id());
                if ( sa.getStaff() != null ){
                    map_obj.put("owner_name", sa.getStaff().getName());
                    map_obj.put("owner_tno", sa.getStaff().getTno());
                }else{
                    map_obj.put("owner_name", "");
                    map_obj.put("owner_tno", "");
                }
                map_obj.put("sftpUsername", sa.getSftpUsername());
                map_obj.put("sftpPassword", sa.getSftpPassword());
                int activateStatus = sa.getActivateStatus();
                if (activateStatus == -1){
                    map_obj.put("activateStatus", "失效");
                }else if (activateStatus == 0){
                    map_obj.put("activateStatus", "未激活");
                }else if (activateStatus == 1){
                    map_obj.put("activateStatus", "激活");
                }
                if ( sa.getCreateTime() != null ){
                    map_obj.put("createTime", Dateutil.getFormatTimeString(Dateutil.myDateutil, sa.getCreateTime()));
                }else{
                    map_obj.put("createTime", "");
                }
                sa_list.add(map_obj);
            }
            p.setList(sa_list);
            msg =  "数据查询成功";
            statusCode = StatusCode.Success._statusCode;
            json.put("page", p);
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json.toJSONString();
    }

    @Override
    public JSONObject queryAllSftpAccountOfStaff(Map<String, Object> requestMap) {
        JSONObject json = new JSONObject();
        String msg = "暂无数据";
        int statusCode = StatusCode.Failure._statusCode;
        // 检查请求参数合法性
        if ( !requestMap.containsKey("userId") || !requestMap.containsKey("pageNum") || !requestMap.containsKey("pageSize") ){
            json.put("msg", "请求参数不合法");
            json.put("statusCode", statusCode);
            return json;
        }
        // 获取参数
        int pageNum = (int) requestMap.get("pageNum");
        int pageSize = (int) requestMap.get("pageSize");
        String user_id = (String) requestMap.get("userId");
        if ( !"".equals(user_id) ){
            PageHelper.startPage(pageNum, pageSize);
            List<SftpAccount> sftpAccounts = sftpAccountMapper.querySftpAccountByStaffId(user_id);
            PageInfo<SftpAccount> pageInfo = new PageInfo<>(sftpAccounts);
            if( sftpAccounts.size() > 0 ) {
                // 由于想自定义分页参数，所以这边只把数据查出来，后边自己封装
                Page<Map<String, Object>> p = new Page<Map<String, Object>>(pageNum, pageSize, (int) pageInfo.getTotal());
                List<Map<String, Object>> sa_list = new ArrayList<>();
                Map<String, Object> map_obj;
                for ( SftpAccount sa : sftpAccounts ) {
                    map_obj = new HashMap<>();
                    map_obj.put("s_a_m_id", sa.getS_a_m_id());
                    if ( sa.getStaff() != null ){
                        map_obj.put("owner_name", sa.getStaff().getName());
                        map_obj.put("owner_tno", sa.getStaff().getTno());
                    }else{
                        map_obj.put("owner_name", "");
                        map_obj.put("owner_tno", "");
                    }
                    map_obj.put("sftpUsername", sa.getSftpUsername());
                    map_obj.put("sftpPassword", sa.getSftpPassword());
                    int activateStatus = sa.getActivateStatus();
                    if (activateStatus == -1){
                        map_obj.put("activateStatus", "失效");
                    }else if (activateStatus == 0){
                        map_obj.put("activateStatus", "未激活");
                    }else if (activateStatus == 1){
                        map_obj.put("activateStatus", "激活");
                    }
                    if ( sa.getCreateTime() != null ){
                        map_obj.put("createTime", Dateutil.getFormatTimeString(Dateutil.myDateutil, sa.getCreateTime()));
                    }else{
                        map_obj.put("createTime", "");
                    }
                    sa_list.add(map_obj);
                }
                p.setList(sa_list);
                msg =  "数据查询成功";
                statusCode = StatusCode.Success._statusCode;
                json.put("page", p);
            }
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json;
    }

    @Override
    public JSONObject queryTreeNodesInfo(Map<String, Object> map) {
        JSONObject json = new JSONObject();
        String msg = "暂无数据";
        int statusCode = StatusCode.Failure._statusCode;
        // 校验参数的合法性
        if ( !map.containsKey("username") || !map.containsKey("password") || !map.containsKey("host") || !map.containsKey("port") || !map.containsKey("path") ){
            json.put("msg", "请求参数不正确");
            json.put("statusCode", statusCode);
            return json;
        }
        // 获取参数
        String username = (String) map.get("username");
        String password = (String) map.get("password");
        String host = (String) map.get("host");
        String port = (String) map.get("port");
        String path = (String) map.get("path");
        if ( "".equals(username) || "".equals(password) || "".equals(host) || "".equals(port) || "".equals(path) ){
            json.put("mag", "参数不可为空");
            json.put("statusCode", statusCode);
            return json;
        }
        int port_ = Integer.parseInt(port);
        // 连接SFTP服务器
        SFTPUtil su = new SFTPUtil(username, password, host, port_);
        boolean login_flag = false;
        try {
            su.login();
            login_flag = true;
        } catch (JSchException e) {
//            e.printStackTrace();
            json.put("msg", "登录验证失败");
            json.put("statusCode", statusCode);
            return json;
        }
        if ( login_flag ){
            Vector<?> objects = null;
            try {
                objects = su.listFiles(path);
            } catch (SftpException e) {
                e.printStackTrace();
            }finally {
                su.logout();
            }
            List<Map<String, Object>> list_current = new ArrayList<>();
            Map<String, Object> temp = null;
            // 判断当前目录下是否有子目录或文件
            if ( objects.size() > 0 ){
                // 目录下内容迭代
                for (int i = 0; i < objects.size(); i++)
                {
                    temp = new HashMap<>();
                    Object obj = objects.elementAt(i);
                    if (obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry)
                    {
                        ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) obj;
                        if (true && !entry.getAttrs().isDir()) // File： have no childNodes
                        {
                            if ( !entry.getFilename().startsWith(".") ){
                                // System.out.println("File= " + entry.getFilename());
                                temp.put("name", entry.getFilename());
                                temp.put("path", path);
                                temp.put("isLeaf", false);
                                temp.put("type", "File");
                                list_current.add(temp);
                            }
                        }
                        if (true && entry.getAttrs().isDir()) // Dir： may have some childNodes
                        {
                            if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")){
                                // System.out.println("Dir= " + entry.getFilename());
                                temp.put("name", entry.getFilename());
                                temp.put("path", path);
                                temp.put("isLeaf", true);
                                temp.put("type", "Dir");
                                list_current.add(temp);
                            }
                        }
                    }
                    //  list_current.add(temp); 这一级会包含"."、".."文件
                }

            }
            json.put("list", list_current);
            msg = "登录成功";
            statusCode = StatusCode.Success._statusCode;
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json;
    }

    // 下载文件
    @Override
    public void sftpDownload(Map<String, Object> requestMap, HttpServletResponse response) {
        System.out.println("now here");
        // 判断请求参数的合法性
        if ( !requestMap.containsKey("username") || !requestMap.containsKey("password") || !requestMap.containsKey("host") || !requestMap.containsKey("port") || !requestMap.containsKey("path") || !requestMap.containsKey("down_filename") )
            return;
        // 获取参数
        String username = (String) requestMap.get("username");
        String password = (String) requestMap.get("password");
        String host = (String) requestMap.get("host");
        String port = (String) requestMap.get("port");
        String path = (String) requestMap.get("path");
        String down_filename = (String) requestMap.get("down_filename");
        if ( "".equals(username) || "".equals(password) || "".equals(host) || "".equals(port) || "".equals(path) || "".equals(down_filename) ){
            return;
        }
        int port_ = Integer.parseInt(port);
        /**
         * @Author Maple.Chen
         * @Description 开始调用SFTPUtil工具下载文件，直接将文件流输出到下载
         * @Date 21:27 2021/4/5
         **/
        SFTPUtil su = new SFTPUtil(username, password, host, port_);
        boolean login_flag = false;
        try {
            su.login();
            login_flag = true;
        } catch (JSchException e) {
//            e.printStackTrace();  //"登录验证失败"
            return;
        }
        if( login_flag ){
            try {
                // 获取文件下载输出流所需要的byte
                byte[] download = su.download(path, down_filename);
                //设置响应头
                response.setContentType("application/octet-stream");
                response.setHeader("content-type", "application/octet-stream");
                response.addHeader("Content-Length", "" + download.length);
                try {
                    response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(down_filename,"utf8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                OutputStream ouputStream = response.getOutputStream();
                ouputStream.write(download);
                ouputStream.close();
                /***
                 * 如果有需求做多个文件压缩下载，首先要得到多个byte[]
                 * byte[] fileByteArray1 = readBytesFromFile("/tmp/mike/1.txt");  方法见本类SFTPServiceImpl
                 */
//                List<byte[]> zip_content_list = new ArrayList<>();
//                zip_content_list.add(download);
//                zip_content_list.add(download);
//                ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
//                ZipOutputStream zip = new ZipOutputStream(baOutputStream);
//                ZipEntry entry = null;
//                int index_count = 1;
//                for ( byte[] blob : zip_content_list ) {
//                    entry = new ZipEntry("a" + Integer.toString(index_count) + "_" + down_filename );
//                    entry.setSize(blob.length);//返回条目数据的未压缩大小；如果未知，则返回 -1。
//                    zip.putNextEntry(entry);// 开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处
//                    zip.write(blob);//将字节数组写入当前 ZIP 条目数据。
//                    zip.closeEntry();
//                    index_count++;
//                }
//                zip.close(); // 压缩流结束
//                byte[] response_blob = baOutputStream.toByteArray();
//                response.reset();
//                response.addHeader("Content-Length", "" + response_blob.length);
//                response.setContentType("application/octet-stream; charset=UTF-8");
//                try {
//                    response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("xxx.zip","utf8"));
//                } catch (UnsupportedEncodingException e) {
//                    e.printStackTrace();
//                }
//                OutputStream ouputStream = response.getOutputStream();
//                ouputStream.write(response_blob);
//                ouputStream.close();  // 下载流结束
            } catch (SftpException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /***
     * 文件转换为byte[]
     */
    private static byte[] readBytesFromFile(String filePath) {
        FileInputStream fileInputStream = null;
        byte[] bytesArray = null;
        try {
            File file = new File(filePath);
            bytesArray = new byte[(int) file.length()];

            //read file into bytes[]
            fileInputStream = new FileInputStream(file);
            fileInputStream.read(bytesArray);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return bytesArray;
    }

}
